package com.mm.fam.common.utils;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.exception.ConflictException;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.exception.NotModifiedException;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.async.ResultCallbackTemplate;

import java.io.IOException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * docker-java utils
 *
 * @author Zhangxd
 * @date 2019年5月16日11:36:08
 */
public class DockerUtils {

    private static final String SERVER_PORT = "2375";
    private static final String IMAGE_NAME_TAG = "javaweb:v2";
    private static final String SYNC_TIME_PATH = "/etc/localtime";
    private static final int CONTAINER_PORT = 8080;
    private static int NUM_STATS = 5;


    /**
     * 创建DockerClient
     *
     * @param ip
     * @return
     */
    public static DockerClient client(String ip) {
        return DockerClientBuilder.getInstance("tcp://" + ip + ":" + SERVER_PORT).build();
    }

    /**
     * 开始容器
     *
     * @param client        句柄
     * @param envs          环境变量
     * @param containerName 容器名称(不可重复)
     * @return
     */
    public static CreateContainerResponse startContainer(DockerClient client, List<String> envs, String containerName) throws Exception {
        return startContainer(client, envs, containerName, IMAGE_NAME_TAG);
    }

    /**
     * 开始容器
     *
     * @param client        句柄
     * @param envs          环境变量
     * @param containerName 容器名称(不可重复)
     * @param imageNameTag  镜像名:标签
     * @return
     */
    public static CreateContainerResponse startContainer(DockerClient client, List<String> envs, String containerName, String imageNameTag) throws Exception {
        CreateContainerResponse container = client.createContainerCmd(imageNameTag)
                .withExposedPorts(ExposedPort.tcp(CONTAINER_PORT))
                .withHostConfig(HostConfig.newHostConfig()
                        .withBinds(new Bind(SYNC_TIME_PATH, new Volume(SYNC_TIME_PATH), AccessMode.ro)))
                .withName(containerName)
                .withEnv(envs)
                .exec();
        client.startContainerCmd(container.getId()).exec();
        return container;
    }

    /**
     * 停止容器
     *
     * @param dockerClient
     * @param containerId
     * @return
     */
    public static boolean stopContainer(DockerClient dockerClient, String containerId) {
        dockerClient.stopContainerCmd(containerId).withTimeout(2).exec();
        dockerClient.removeContainerCmd(containerId).exec();
        List<Container> containers = dockerClient.listContainersCmd().withShowAll(true).exec();
        for (Container c : containers) {
            if (c.getId().contains(containerId))
                return false;
        }
        return true;
    }

    /**
     * 查看状态
     *
     * @param dockerClient
     * @param containerId
     * @return
     */
    public static boolean statusContainer(DockerClient dockerClient, String containerId) {
        InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(containerId).exec();
        return inspectContainerResponse.getState().getExitCode().equals(0) && inspectContainerResponse.getState().getRunning() ? true : false;
    }


    public static void main(String[] args) throws InterruptedException, IOException {
        String url = "tcp://192.168.1.230:2375";
        // 简单方式登录docker
        DockerClient dockerClient = DockerClientBuilder.getInstance(url).build();
        final String DEFAULT_IMAGE = "javaweb:v2";
        /**
         * 根据名称查找镜像
         * 创建实例
         */
        String containerName = "generated_" + new SecureRandom().nextInt();
        // 映射端口
        Ports portBindings = new Ports();
//        portBindings.bind(ExposedPort.tcp(8080), Ports.Binding.bindPort(8086));

        // 环境变量集合
        List<String> envs = new ArrayList<>();
        envs.add("m_BrokerId=9999");
        envs.add("m_UserId=990003");

        // 创建容器
        // 创建如果找不到镜像   NotFoundException错误

        CreateContainerResponse container = null;
        try {
            container = dockerClient.createContainerCmd(DEFAULT_IMAGE)
                    .withExposedPorts(ExposedPort.tcp(8080))
                    .withName(containerName)
                    .withEnv(envs)
                    .exec();
            dockerClient.startContainerCmd(container.getId()).exec();

            dockerClient.stopContainerCmd(container.getId()).withTimeout(2).exec();

            dockerClient.removeContainerCmd(container.getId()).exec();

            List<Container> containers2 = dockerClient.listContainersCmd().withShowAll(true).exec();
            for (Container container1 : containers2) {
                if (container1.getId().contains(container.getId())) {
                    System.out.println("存在---------------------------");
                }
            }


            // 正确回执
//        exitcode:0
//        running:true
//        dead:false
//        error:
            // 停止回执
//            exitcode:137
//            running:false
//            dead:false
//            error:
            // 方式1 判断是否创建成功
//            InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec();
//            System.out.println("exitcode:" + inspectContainerResponse.getState().getExitCode());
//            System.out.println("running:" + inspectContainerResponse.getState().getRunning());
//            System.out.println("dead:" + inspectContainerResponse.getState().getDead());
//            System.out.println("error:" + inspectContainerResponse.getState().getError());

            // 方式2 判断是否创建成功
//            CountDownLatch countDownLatch = new CountDownLatch(NUM_STATS);
//            StatsCallbackTest statsCallback = dockerClient.statsCmd(container.getId()).exec(
//                    new StatsCallbackTest(countDownLatch));
//            countDownLatch.await(3, TimeUnit.SECONDS);
//            Boolean gotStats = statsCallback.gotStats();
//            System.out.println("status:"+gotStats);
        } catch (NotFoundException e) {
            System.out.println("未找到镜像");
            e.printStackTrace();
        } catch (ConflictException e) {
            System.out.println("发生冲突");
            e.printStackTrace();
        } catch (NotModifiedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            System.out.println("创建失败");
        }


        // 启动回执
//        Integer test = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode();
//        // 查看启动状态 getRunning 只能查看停止状态   ???????????????
//        System.out.println("--------------" + test);

//        WaitContainerResultCallback callback = dockerClient.waitContainerCmd(container.getId()).exec(
//                new WaitContainerResultCallback());
//        Thread.sleep(5000);
//        callback.close();
//        System.out.println(callback.awaitStatusCode()+"----------------------");

//        dockerClient.killContainerCmd(container.getId()).exec();
        // 启动失败   状态为1    成功返回是137  不确定是否为成功返回 暂只判断失败
//        if(callback.awaitStatusCode()==1){
//            dockerClient.killContainerCmd(container.getId()).exec();
//        }
//        InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec();
//        System.out.println("容器是否启动:" + inspectContainerResponse.getState().getRunning());
//        System.out.println("容器是否启动state:" + inspectContainerResponse.getState().getStatus());
    }


    private static class StatsCallbackTest extends ResultCallbackTemplate<StatsCallbackTest, Statistics> {
        private final CountDownLatch countDownLatch;

        private Boolean gotStats = false;

        public StatsCallbackTest(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void onNext(Statistics stats) {
            if (stats != null) {
                gotStats = true;
            }
            countDownLatch.countDown();
        }

        public Boolean gotStats() {
            return gotStats;
        }
    }

    public static void old_test(String[] args) throws InterruptedException, IOException {
        String url = "tcp://192.168.1.230:2375";
        // 简单方式登录docker
        DockerClient dockerClient = DockerClientBuilder.getInstance(url).build();
        final String DEFAULT_IMAGE = "java:8";
        /**
         * 根据名称查找镜像
         * 创建实例
         */
        String containerName = "generated_" + new SecureRandom().nextInt();
        // 映射端口
        Ports portBindings = new Ports();
        portBindings.bind(ExposedPort.tcp(8080), Ports.Binding.bindPort(8086));

        // 绑定卷轴
        Volume volume = new Volume("/usr/software/testenv.jar");

        // 环境变量集合
        List<String> envs = new ArrayList<>();
        envs.add("m_BrokerId=9999");
        envs.add("m_UserId=990003");
        envs.add("m_InvestorId=990003");
        envs.add("m_PassWord=147258");
        envs.add("m_UserName=汪云飞");
        envs.add("m_TradingDay=20190102");
        envs.add("m_PriorityCash=40000.0");
        envs.add("m_OvernightMarginMultiple=2.0");
        // 创建容器
        CreateContainerResponse container = dockerClient.createContainerCmd(DEFAULT_IMAGE)
                .withExposedPorts(ExposedPort.tcp(8080))
                .withName(containerName)
                .withHostConfig(HostConfig.newHostConfig()
                                .withBinds(new Bind("/usr/software/testenv.jar", volume))
//                        .withPortBindings(portBindings)
                )
                .withEnv(envs)
                .withCmd("java", "-jar", "/usr/software/testenv.jar")
                .exec();
        // 启动容器
        dockerClient.startContainerCmd(container.getId()).exec();
        System.out.println("容器ID" + container.getId());

        // 启动回执
//        Integer test = dockerClient.waitContainerCmd(container.getId()).exec(new WaitContainerResultCallback()).awaitStatusCode();
//        // 查看启动状态 getRunning 只能查看停止状态   ???????????????
//        System.out.println("--------------" + test);

//        WaitContainerResultCallback callback = dockerClient.waitContainerCmd(container.getId()).exec(
//                new WaitContainerResultCallback());
//        Thread.sleep(5000);
//        callback.close();
//        System.out.println(callback.awaitStatusCode()+"----------------------");

//        dockerClient.killContainerCmd(container.getId()).exec();
        // 启动失败   状态为1    成功返回是137  不确定是否为成功返回 暂只判断失败
//        if(callback.awaitStatusCode()==1){
//            dockerClient.killContainerCmd(container.getId()).exec();
//        }
//        InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec();
//        System.out.println("容器是否启动:" + inspectContainerResponse.getState().getRunning());
//        System.out.println("容器是否启动state:" + inspectContainerResponse.getState().getStatus());
    }


}
